const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const JSZip = require('jszip');
const { promisify } = require('util');
const writeFileAsync = promisify(fs.writeFile);

function rmrf(targetPath) {
	if (fs.existsSync(targetPath)) {
		fs.rmSync(targetPath, { recursive: true, force: true });
	}
}

function mkdirp(dirPath) {
	fs.mkdirSync(dirPath, { recursive: true });
}

function cp(src, dest) {
	if (!fs.existsSync(src)) return;
	const stat = fs.statSync(src);
	if (stat.isDirectory()) {
		mkdirp(dest);
		for (const file of fs.readdirSync(src)) {
			cp(path.join(src, file), path.join(dest, file));
		}
	} else {
		mkdirp(path.dirname(dest));
		fs.copyFileSync(src, dest);
	}
}

function mv(src, dest) {
	if (!fs.existsSync(src)) return;
	mkdirp(path.dirname(dest));
	fs.renameSync(src, dest);
}

function getVersion() {
	// 读取 src/version.js 文件中的版本号
	const versionFile = path.join(__dirname, 'src', 'version.js');
	const content = fs.readFileSync(versionFile, 'utf8');
	const match = content.match(/[0-9]+\.[0-9]+\.[0-9]+/);
	return match ? match[0] : 'unknown';
}

function run(cmd) {
	console.log('> ' + cmd);
	execSync(cmd, { stdio: 'inherit' });
}

function build() {
	run('yarn build');
}



function packNwjs() {
	const tmpDir = path.join('platform', 'nw.js', 'tmp');
	console.log(`[清理] 删除目录: ${tmpDir}`);
	rmrf(tmpDir);
	console.log(`[创建] 创建目录: ${tmpDir}`);
	mkdirp(tmpDir);
	const sdkSrc = path.join('platform', 'nw.js', 'nwjs-sdk-v0.51.2-win-x64');
	console.log(`[复制] ${sdkSrc} -> ${tmpDir}`);
	cp(sdkSrc, tmpDir);
	console.log(`[复制] dist -> ${tmpDir}`);
	cp('dist', tmpDir);
	const assetsDir = path.join(tmpDir, 'assets');
	console.log(`[创建] 创建目录: ${assetsDir}`);
	mkdirp(assetsDir);
	const efuseSrc = path.join('platform', 'nw.js', 'assets', 'efuse-bin');
	const efuseDest = path.join(assetsDir, 'efuse-bin');
	console.log(`[复制] ${efuseSrc} -> ${efuseDest}`);
	cp(efuseSrc, efuseDest);
	const firmwareSrc = path.join('platform', 'nw.js', 'assets', 'firmware');
	const firmwareDest = path.join(assetsDir, 'firmware');
	console.log(`[复制] ${firmwareSrc} -> ${firmwareDest}`);
	cp(firmwareSrc, firmwareDest);
	const toolsSrc = path.join('platform', 'nw.js', 'assets', 'tools');
	const toolsDest = path.join(assetsDir, 'tools');
	console.log(`[复制] ${toolsSrc} -> ${toolsDest}`);
	cp(toolsSrc, toolsDest);
	const nwExe = path.join(tmpDir, 'nw.exe');
	const beconsoleExe = path.join(tmpDir, 'BeConsole.exe');
	if (fs.existsSync(nwExe)) {
		console.log(`[重命名] ${nwExe} -> ${beconsoleExe}`);
		mv(nwExe, beconsoleExe);
	}
}

function win64() {
	build();
	packNwjs();
}


async function zipDirectory(sourceDir, outPath) {
	const zip = new JSZip();
	async function addDirToZip(zipObj, dir, zipPath = '') {
		const items = fs.readdirSync(dir);
		for (const item of items) {
			const fullPath = path.join(dir, item);
			const relPath = path.join(zipPath, item);
			const stat = fs.statSync(fullPath);
			if (stat.isDirectory()) {
				const folder = zipObj.folder(item);
				await addDirToZip(folder, fullPath, relPath);
			} else {
				zipObj.file(item, fs.readFileSync(fullPath));
			}
		}
	}
	await addDirToZip(zip, sourceDir);

	let lastMsgLen = 0;
	const content = await zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE' }, (metadata)=>{
		const msg = `${metadata.percent.toFixed(2)}%  ${metadata.currentFile || ''}`;
		let padLen = 0;
		if (lastMsgLen > msg.length) {
			padLen = lastMsgLen - msg.length;
		}
		process.stdout.write(`\r${msg}${' '.repeat(padLen)}`);
		lastMsgLen = msg.length;
	});
	process.stdout.write('\n');
	await writeFileAsync(outPath, content);
}

async function zipWin64() {
		const version = getVersion();
		const tmpDir = path.join('platform', 'nw.js', 'tmp');
		const beconsoleDir = path.join('platform', 'nw.js', `BeConsole-${version}-win64`);
		const releaseDir = path.join('platform', 'nw.js', 'release');
		const zipFile = path.join(releaseDir, `BeConsole-${version}-win64.zip`);
		console.log(version);
			if (!fs.existsSync(tmpDir)) {
				console.error(`[错误] 未找到目录: ${tmpDir}，请先执行 pack 命令。`);
				console.error(``);
				console.error(`       node make.js pack`);
				console.error(``);
				return;
			}
			mv(tmpDir, beconsoleDir);
			rmrf(zipFile);
			console.log(`[压缩] ${beconsoleDir} -> ${zipFile}`);
			// 输出所有文件
			function listFiles(dir, prefix = '') {
				let files = [];
				for (const item of fs.readdirSync(dir)) {
					const fullPath = path.join(dir, item);
					const relPath = path.join(prefix, item);
					if (fs.statSync(fullPath).isDirectory()) {
						files = files.concat(listFiles(fullPath, relPath));
					} else {
						files.push(relPath);
					}
				}
				return files;
			}
			const fileList = listFiles(beconsoleDir);
			console.log(`[文件列表]`);
			// fileList.forEach(f => console.log('  ' + f));
			zipDirectory(beconsoleDir, zipFile)
				.then(() => {
					console.log(`[完成] ZIP 文件已生成: ${zipFile}`);
					mv(beconsoleDir, tmpDir);
				})
				.catch((e) => {
					console.error('压缩失败:', e);
					mv(beconsoleDir, tmpDir);
				});
}


function release() {
	packNwjs();
	zipWin64();
}

let cmd = process.argv[2] || 'help';

switch (cmd) {
	case 'build':
		build();
		break;
	case 'pack':
		packNwjs();
		break;
	case 'win64':
		win64();
		break;
	case 'zip':
	case 'zip-win64':
		zipWin64();
		break;
	case 'release':
		release();
		break;
	case 'upload-win64':
		uploadWin64();
		break;
	case 'all':
		all();
		break;
	case 'help':
	case '?':
	default:
		console.log(`
Usage: node make.js <command>

Commands:
	build         构建前端 dist 目录 (yarn build)
	pack          打包 NW.js 运行环境和 dist 到 platform/nw.js/tmp
	win64         构建并打包 NW.js win64 版本 (build + pack)
	zip-win64     生成 zip 包: BeConsole-<version>-win64.zip
	release       完整发布流程 (pack + zip-win64)
	upload-win64  上传 zip 包到远程服务器
	all           等同于 win64 + zip-win64

流程说明：
	1. build         编译 vue 输出到 dist 目录
	2. pack          整合完整文件，包括： nwjs-sdk、dist、assets 到 tmp 目录
	3. win64         等同于 build + pack
	4. zip-win64     将 tmp 目录重命名为 BeConsole-<version>-win64 并压缩，可用于分发
	5. release       执行 pack 和 zip-win64
	6. upload-win64  上传 zip 包到服务器

示例：
	node make.js build
	node make.js pack
	node make.js win64
	node make.js zip-win64
	node make.js release
	node make.js upload-win64
	node make.js all
`);
		break;
}
